import Flutter
import UIKit
import yasee_ios

public class YaseePlugin: NSObject {
    static let single = YaseePlugin()
    private override init() {
        Notify.single.listen(notifyDevices)
        Notify.single.listen(notifyBle)
        Notify.single.listen(notifyData)
    }
    private var sink: FlutterEventSink!
    
    /// 设备变更产生的通知
    private let notifyDevices : NotifyCall<NotifyBleDevice> = { single.send($0) }
    
    /// 蓝牙状态产生的通知
    private let notifyBle : NotifyCall<NotifyBleState> = { single.send($0) }
    
    /// 设备产生的交互数据
    private let notifyData : NotifyCall<NotifyDeviceData> = { single.sendData($0) }
}


// MARK: RR 响应
extension YaseePlugin: FlutterPlugin {
    
    public static func register(with registrar: FlutterPluginRegistrar) {
        let channel = FlutterMethodChannel(name: "yasee_plugin", binaryMessenger: registrar.messenger())
        let event = FlutterEventChannel(name: "yasee_plugin_event", binaryMessenger: registrar.messenger())
        registrar.addMethodCallDelegate(single, channel: channel)
        event.setStreamHandler(single)
        let _ = Yasee.single
    }
    
    
    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        switch call.method {
// MARK: ============================================ 配置信息
        case "configBle": // 配置 蓝牙 设置信息
            guard let args = call.arguments as? [String:Any], let reconnect = args["reconnect"] as? Bool, let scanTime = args["scanTime"] as? Double else { return }
            Yasee.single.bleConfig.reconnect = reconnect
            Yasee.single.bleConfig.scanTime = scanTime
            result(FlutterMethodNotImplemented)
        case "configUser": // 配置 人员信息
            guard 
                let args = call.arguments as? [String:Any],
                let sex = args["sex"] as? Int,
                let age = args["age"] as? Int,
                let smoking = args["smoking"] as? Int,
                let height = args["height"] as? Int,
                let weight = args["weight"] as? Int
            else {
                result(ErrObj.noWay.json)
                return
            }
            Yasee.single.user = User(sex: sex, age: age, smoking: smoking, height: height, weight: weight)
            result(nil)
        case "configDevices": // 设置 初始的 绑定设备
            
            guard
                let dds = call.arguments as? [[String:Any]]
            else {
                result(ErrObj.noWay.json)
                return
            }
            
            // 延迟2秒执行
            DispatchQueue.global().asyncAfter(deadline: .now() + 2.0) {
                do {
                    let data = try JSONSerialization.data(withJSONObject: dds)
                    let devices = try JSONDecoder().decode([BleDevice].self, from: data)
                    if devices.isEmpty { return }
                    DispatchQueue.main.async {
                        Yasee.single.initDevices(devices)
                    }
                    
                    
                    result(nil)
                } catch let err {
                    result(ErrObj(code: 0xE9, desc: err.localizedDescription, suggestion: "请联系客服").json)
                }
            }
            
// MARK: ============================================ 蓝牙相关的操作
        case "scan": // 搜索
            Yasee.single.scan()
            result(nil)
        case "stop": // 结束搜索
            Yasee.single.stop()
            result(nil)
            
// MARK: ============================================ 设备相关的设置
        case "bind": // 绑定设备
            guard
                let args = call.arguments as? [String:Any],
                let mac = args["mac"] as? String,
                let model = args["model"] as? String,
                let dd = (Devices.single.allSearchs.first { $0.hMac == mac }),
                !(Devices.single.allBinds.contains { $0.hMac == mac })
            else {
                result(ErrObj.noFound.json)
                return
            }
            dd.connect()
            result(nil)
        case "reconnect": // 重连设备
            guard
                let mac = call.arguments as? String,
                let dd = (Devices.single.allBinds.first { $0.hMac == mac })
            else {
                result(ErrObj.noFound.json)
                return
            }
            dd.reconnect()
            result(nil)
        case "cancel": // 解绑设备
            guard
                let mac = call.arguments as? String,
                let dd = (Devices.single.allBinds.first { $0.hMac == mac })
            else {
                result(ErrObj.noFound.json)
                return
            }
            Yasee.single.unBinds([dd])
            result(nil)
        case "checks": // 获取设备支持的检测项
            guard
                let mac = call.arguments as? String,
                let dd = (Devices.single.allBinds.first { $0.hMac == mac }),
                let json = dd.supportChecks.json
            else {
                result(ErrObj.noFound.json)
                return
            }
            result(json)
            
        case "cmds": // 获取检测项支持的 指令集
            guard
                let handware = call.arguments as? Int
            else {
                result(ErrObj.noFound.json)
                return
            }
            let check = Check("", handware)
            guard let json = check.cmds.json else {
                result(ErrObj.noFound.json)
                return
            }
            result(json)
            
        case "send": // 发送指令
            guard
                let map = call.arguments as? [String:Any],
                let mac = map["mac"] as? String,
                let device = (Devices.single.allBinds.first { $0.hMac == mac }),
                let handware = map["handware"] as? Int,
                let cmdId = map["cmdId"] as? String,
                let parms = map["parms"] as? [String:Any]
            else {
                result(ErrObj.noFound.json)
                return
            }
            let check = Check("", handware)
            guard let cmd = (check.cmds.first { $0.id.uuidString == cmdId }) else {
                result(ErrObj.noFound.json)
                return
            }
            do {
                try device.send(handware, cmdId, parms)
            } catch let err {
                print(err.localizedDescription);
            }
            result(nil);
        case "sendCustom":  // 发送自定义数据
            guard
                let args = call.arguments as? [String:Any],
                let mac = args["mac"] as? String,
                let data = args["data"] as? FlutterStandardTypedData,
                let dd = (Devices.single.allBinds.first { $0.hMac == mac })
            else {
                result(ErrObj.noFound.json)
                return
            }
            do {
                try dd.send(data.data)
            } catch let err {
                print(err.localizedDescription);
            }
            result(nil)
        default:
          result(FlutterMethodNotImplemented)
        }
    }
    
}





// MARK:  发送 数据流
extension YaseePlugin : FlutterStreamHandler {
    
    
    /// 发送 数据流
    func send<C>(_ data: C) where C : Codable {
        if self.sink == nil { return }
        guard let json = data.json else { return }
        DispatchQueue.main.async { self.sink(json) }
    }
    /// 发送Data
    func sendData(_ data: NotifyResp<NotifyDeviceData>) {
        if self.sink == nil { return }
        
        do {
            guard
                var json = data.json as? [String: Any],
                var _data = json["data"] as? [String: Any],
                let dict = try JSONSerialization.jsonObject(with: data.data.data) as? [String: Any]
            else { return }
            
            _data["data"] = dict
            
            json["data"] = _data
            
            DispatchQueue.main.async { self.sink(json) }
        } catch let err {
            print("错误: \(err.localizedDescription)")
        }
        
        
    }
    
    public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
        sink = events
//        return .init(code: "400", message: "未知信息", details: "参数:\(arguments.debugDescription)")
        return nil
    }
    
    public func onCancel(withArguments arguments: Any?) -> FlutterError? {
        sink = nil
        return nil;
//        return .init(code: "400", message: "未知信息", details: "参数:\(arguments.debugDescription)")
    }
}
